//
//  3DDemoView.swift
//  HelloSwiftUI
//
//  Created by kuangxianming on 2024/5/29.
//

import SwiftUI
import SceneKit
import SpriteKit

// 假设有四个预定义类别
let CategoryObstacle = 1 << 0 // 0001
let CategoryPlayer = 1 << 1 // 0010
let CategoryEnemy = 1 << 2 // 0100
let CategoryCollectible = 1 << 3 // 1000

struct ThreeDDemoView: View {
    
    let scene = SCNScene()
    @State var showAlert: Bool = false
    @State var alertContent: String = ""
    
    var body: some View {
        // 使用UIViewRepresentable协议桥接SceneKit视图到SwiftUI
        SceneKitView(scene: scene, showAlert: $showAlert, alertText: $alertContent)
            .frame(width: 360, height: 360)
            .alert(isPresented: self.$showAlert) {
                Alert(
                    title: Text(self.alertContent)
                )
            }
    }
}

class NodeContainer:NSObject {
    var nNodes = Array<SCNNode>()
}

// 通过UIViewRepresentable协议将SceneKit视图转换为SwiftUI视图
struct SceneKitView: UIViewRepresentable {
    let scene: SCNScene
    private let scnView = SCNView()
    
    @Binding var showAlert: Bool
    @Binding var alertText: String
    
    private let narmalNodes = NodeContainer()
    

    func makeUIView(context: Context) -> SCNView {
        
        scnView.scene = scene
        // 开启抗锯齿，提升显示效果
        scnView.antialiasingMode = .multisampling4X
        // 允许用户交互（如旋转、缩放）
        scnView.allowsCameraControl = true
        
//        scnView.debugOptions = [.showWireframe]// 打开调试模型即可
        
        scnView.autoenablesDefaultLighting = true
//        scnView.shadowMapSize = CGSize(width: 2048, height: 2048) // 可调整阴影贴图的分辨率
//        scnView.lightingEnvironment.contents = SCNScene(named: "yourHDRImage.exr")?.environmentContents // 如果使用HDR照明
        
//        // 添加点击手势识别器
        let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap(_:)))
        scnView.addGestureRecognizer(tapGesture)
//        
//        let panGesture = UIPanGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handlePanGesture(_:)))
//        scnView.addGestureRecognizer(panGesture)
//        
//        let pinchGesture = UIPinchGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handlePinchGesture(_:)))
//        scnView.addGestureRecognizer(pinchGesture)
//        
//        let rotationGesture = UIRotationGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleRotationGesture(_:)))
//        scnView.addGestureRecognizer(rotationGesture)
//        
//        // 配置物理世界
//        let physicsWorld = scene.physicsWorld
//        physicsWorld.contactDelegate = context.coordinator // 设置代理
        
        // 这里可以更新场景内容，比如添加3D模型、灯光等
        let light = SCNLight()
        light.type = .directional // 或者 .spot
        light.castsShadow = true
        
        let lightNode = SCNNode()
        lightNode.light = light
        lightNode.position = SCNVector3(x: 0, y: 10, z: 0) // 例如，将灯光放在场景上方
        lightNode.eulerAngles = SCNVector3(x: -Float.pi / 3, y: 0, z: 0) // 使灯光从左上角照射下来
        
        // 设置光源的位置或方向
        scene.rootNode.addChildNode(lightNode)
        
        // 添加坐标轴
        self.addAxis()
        // 添加平面，作为地面
        self.creatFloor()
        
        // 添加立方体
        self.creatBox()
        
        // 添加默认相机
        self.setupCamera(in: scene.rootNode)
        
        // 添加一个单独操控的对象
//        self.addFreeObj()
//        self.addCustomFreeObj()
    
//        self.addFreeObj()
//        self.addFreeObj2()
//        let customNode = BaseNode()
        return scnView
    }

    func updateUIView(_ uiView: SCNView, context: Context) {


    }
    
    func setupCamera(in parentNode: SCNNode) {
        // 创建摄像机节点
        let cameraNode = SCNNode()
        let camera = SCNCamera()
        
        // 配置摄像机属性（如视场角、投影模式等）
        camera.fieldOfView = 60 // 以度为单位的视场角，默认为60度
        // 其他相机属性可以根据需要设置，例如camera.zNear, camera.zFar等
        
        // 将摄像机附加到摄像机节点
        cameraNode.camera = camera
        
        // 设置摄像机的位置，例如在场景的(0, 0, 5)，意味着摄像机位于原点前方5个单位
        cameraNode.position = SCNVector3(x: 0, y: 4, z: 10)
        cameraNode.look(at: SCNVector3(x: 0, y: 0, z: 0))
        cameraNode.name = "cameraNode"
        
        // 将摄像机节点添加到场景的根节点
        parentNode.addChildNode(cameraNode)
        
        // 如果有需要，可以设置摄像机作为主摄像机
        // sceneView.pointOfView = cameraNode // 在SwiftUI的SceneView中，这一步可能不需要显式设置
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, SCNPhysicsContactDelegate, SCNSceneRendererDelegate {
        var parent: SceneKitView
        var selectNode: SCNNode?
        var materialOfSelectNode: Any?

        init(_ parent: SceneKitView) {
            
            self.parent = parent
        
        }
        
        func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
                // 在此处添加您的渲染回调逻辑
            print("渲染回调被调用")
            
            let cubeNode = parent.scnView.scene?.rootNode.childNode(withName: "我是盒子", recursively: true)
            
            parent.getTopFaceIndex(node: cubeNode!)
        }
        

        @objc func handleTap(_ gestureRecognizer: UITapGestureRecognizer) {
            
            parent.scnView.delegate = self
            
//            let location = gestureRecognizer.location(in: parent.scnView)
//            let hitResults = parent.scnView.hitTest(location, options: [:])
//
//            if let firstHit = hitResults.first {
//                let node = firstHit.node
//                // 处理点击的节点
//                print("Tapped on node: \(node.name ?? "Unnamed Node")")
//
//                if (self.selectNode != nil)
//                {
//                    // 先还原之前选择的node
//                    self.selectNode?.geometry?.firstMaterial?.diffuse.contents = self.materialOfSelectNode
//                }
//                
//                self.selectNode = node;
//                self.materialOfSelectNode = node.geometry?.firstMaterial?.diffuse.contents;
//            
//                node.geometry?.firstMaterial?.diffuse.contents = UIColor.red
//            }
//            
//            let 🌨 = -10, 🌤 = 10, 💧 = 0
//            
//            let 中古 = -10
//            
//            if combinedWeatherConditions(中古, 🌤) == 💧 {
//                print("😔 — No 🏂 Today.")
//            }
            
            let cubeNode = parent.scnView.scene?.rootNode.childNode(withName: "我是盒子", recursively: true)
            
//            parent.rollTheBox(node: cubeNode!)
            parent.rollDice(diceNode: cubeNode!)
                    
        
        }
            // 处理平移手势的方法
        @objc func handlePanGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
            // 确保有一个相机节点存在
            guard let cameraNode = parent.scnView.scene?.rootNode.childNode(withName: "cameraNode", recursively: true),
                  let camera = cameraNode.camera else {
                return
            }

            // 获取手势的状态
            switch gestureRecognizer.state {
            case .began, .changed:
                // 计算平移向量
                let translation = gestureRecognizer.translation(in: parent.scnView)
                // 更新相机位置
                let cameraPosition = cameraNode.position
                let panSpeed: CGFloat = 0.03 // 控制平移速度
                let x = translation.x * panSpeed
                let y = translation.y * panSpeed
                let newPosition = SCNVector3(
                    x: cameraPosition.x - Float(x),
                    y: cameraPosition.y + Float(y),
                    z: cameraPosition.z
                )
                // 限制相机的Y轴移动，以避免从底部或顶部穿出场景
                let newY = min(max(newPosition.y, 0), 100) // 假设场景的最大高度为100
                cameraNode.position = SCNVector3(newPosition.x, newY, newPosition.z)
                // 重置translation，以便下次手势改变时能继续平移
                gestureRecognizer.setTranslation(.zero, in: parent.scnView)
            default:
                break
            }
        }
        
        @objc func handlePinchGesture(_ gestureRecognizer: UIPinchGestureRecognizer) {
            guard gestureRecognizer.state == .changed,
                  let pointOfView = parent.scnView.pointOfView else { return }
            
            // 根据pinch手势的scale属性调整相机的缩放
            let scale = gestureRecognizer.scale
            pointOfView.scale = SCNVector3(1, 1, scale) // 假设只在Z轴上缩放，保持X和Y方向不变
            gestureRecognizer.scale = 1 // 重置缩放值以避免累积
        }
        
        @objc func handleRotationGesture(_ gestureRecognizer: UIRotationGestureRecognizer) {
            guard gestureRecognizer.state == .changed,
                  let pointOfView = parent.scnView.pointOfView else { return }
            
            // 计算旋转角度增量，并应用到相机的Y轴旋转
            let rotation = Float(gestureRecognizer.rotation)
            gestureRecognizer.rotation = 0 // 重置旋转值以避免累积
            let currentRotation = pointOfView.eulerAngles.y
            let newRotation = currentRotation + rotation // 增量旋转
            pointOfView.eulerAngles.y = newRotation
        }
        
        func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact){
//            print("***didBegin " + contact.nodeA.name! + " contact " + contact.nodeB.name!)
        }
        func physicsWorld(_ world: SCNPhysicsWorld, didUpdate contact: SCNPhysicsContact){
//           print("***didUpdate " + contact.nodeA.name! + " contact " + contact.nodeB.name!)
        }

        func physicsWorld(_ world: SCNPhysicsWorld, didEnd contact: SCNPhysicsContact){
//            print("***didEnd " + contact.nodeA.name! + " contact " + contact.nodeB.name!)
        }
        
        func combinedWeatherConditions(_ lhs: Int, _ rhs: Int) -> Int {
            return lhs + rhs
        }

    }
    
    func creatBox()
    {
        // 示例：添加一个简单的立方体
        let box = SCNBox(width: 2.0, height: 2.0, length: 2.0, chamferRadius: 0)
        
        numberMaterials(box: box)
        
        
//        box.firstMaterial?.diffuse.contents = UIColor.yellow
        
//        let n = box.firstMaterial?.normal

        
        let cubeNode = SCNNode(geometry: box)
        cubeNode.position = SCNVector3(x: 1, y: 3, z: 1)
        scene.rootNode.addChildNode(cubeNode)

        cubeNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(geometry: box, options: nil))
//        cubeNode.physicsBody?.mass = 1.0
//        cubeNode.physicsBody?.friction = 0.5
//        cubeNode.physicsBody?.restitution = 0.3 // 弹性
        cubeNode.name = "我是盒子"
        

        // 确保你的图片文件已添加到项目中，并使用正确的命名
//        guard let textureImage = UIImage(named: "texture.png") else { return }
//
//        // 检查纹理图像是否加载成功
//        let texture = SKTexture(image: textureImage)
//        let material = SCNMaterial()
//        material.lightingModel = .physicallyBased
//        material.writesToDepthBuffer = true
//        
//        material.diffuse.contents = texture
//        box.materials = [material] // 将材质应用到立方体几何体上
     
//        getTopFaceIndex(node: cubeNode)
        
//        rollTheBox(node: cubeNode)
        
        let v = box.sources(for: .vertex)
        let n = box.sources(for: .normal)
        
        let vertices = getVertices(from: v[0])
        
        print("box size (\(box.width), \(box.height), \(box.length))")
    
    }
    
    func colorMaterials(box: SCNGeometry) {
        let material1 = SCNMaterial()
        material1.lightingModel = .physicallyBased
        material1.writesToDepthBuffer = true
        material1.diffuse.contents = UIColor.red
        
        let material2 = SCNMaterial()
        material2.lightingModel = .physicallyBased
        material2.writesToDepthBuffer = true
        material2.diffuse.contents = UIColor.white
        
        let material3 = SCNMaterial()
        material3.lightingModel = .physicallyBased
        material3.writesToDepthBuffer = true
        material3.diffuse.contents = UIColor.blue
        
        let material4 = SCNMaterial()
        material4.lightingModel = .physicallyBased
        material4.writesToDepthBuffer = true
        material4.diffuse.contents = UIColor.green
        
        let material5 = SCNMaterial()
        material5.lightingModel = .physicallyBased
        material5.writesToDepthBuffer = true
        material5.diffuse.contents = UIColor.purple
        
        let material6 = SCNMaterial()
        material6.lightingModel = .physicallyBased
        material6.writesToDepthBuffer = true
        material6.diffuse.contents = UIColor.gray
        
        box.materials = [
            material1,
            material2,
            material3,
            material4,
            material5,
            material6
        ]
    }
    
    func numberMaterials(box: SCNGeometry) {
        
        let font = UIFont.systemFont(ofSize: 64)
        let color = UIColor.white
        
        let textureImage1 = createTextTexture(text: "1", font: font, color: color, bgColor: .red)
        let material1 = SCNMaterial()
        material1.lightingModel = .physicallyBased
        material1.writesToDepthBuffer = true
        material1.diffuse.contents = textureImage1
        
        let textureImage2 = createTextTexture(text: "2", font: font, color: color, bgColor: .white)
        let material2 = SCNMaterial()
        material2.lightingModel = .physicallyBased
        material2.writesToDepthBuffer = true
        material2.diffuse.contents = textureImage2
        
        let textureImage3 = createTextTexture(text: "3", font: font, color: color, bgColor: .lightGray)
        let material3 = SCNMaterial()
        material3.lightingModel = .physicallyBased
        material3.writesToDepthBuffer = true
        material3.diffuse.contents = textureImage3
        
        let textureImage4 = createTextTexture(text: "4", font: font, color: color, bgColor: .green)
        let material4 = SCNMaterial()
        material4.lightingModel = .physicallyBased
        material4.writesToDepthBuffer = true
        material4.diffuse.contents = textureImage4
        
        let textureImage5 = createTextTexture(text: "5", font: font, color: color, bgColor: .purple)
        let material5 = SCNMaterial()
        material5.lightingModel = .physicallyBased
        material5.writesToDepthBuffer = true
        material5.diffuse.contents = textureImage5
        
        let textureImage6 = createTextTexture(text: "6", font: font, color: color, bgColor: .gray)
        let material6 = SCNMaterial()
        material6.lightingModel = .physicallyBased
        material6.writesToDepthBuffer = true
        material6.diffuse.contents = textureImage6
        
        box.materials = [
            material1,
            material2,
            material3,
            material4,
            material5,
            material6
        ]
    }

    func rollTheBox(node: SCNNode) {
        
        // 先移除旧向量
        for node in self.narmalNodes.nNodes {
            node.removeFromParentNode();
        }
        
        self.narmalNodes.nNodes.removeAll()
        
        node.physicsBody?.isAffectedByGravity = false
        
        // 使用SCNTransaction开始一个动画块
        SCNTransaction.begin()
        SCNTransaction.animationDuration = 3.0 // 动画持续时间
        SCNTransaction.animationTimingFunction = CAMediaTimingFunction(name: .easeInEaseOut) // 动画缓动效果

        
        // 2. 应用随机旋转力来模拟摇动
//        let rotationAngle = Float.random(in: 0..<2 * Float(CGFloat.pi)) // 随机旋转角度
        let faceIndex = Int.random(in: 0..<4)
        let rotationAngle = Float(faceIndex) * Float(CGFloat.pi * 0.5) // 随机旋转角度
        // 旋转节点
        node.rotation = SCNVector4(1, 0, 0, rotationAngle) // 使节点围绕Y轴旋转360度
//        node.transform =

        // 结束动画块
        SCNTransaction.commit()
        
        // 3. 在动画结束后，恢复物理效果并检测点数
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            node.physicsBody?.isAffectedByGravity = true
            node.physicsBody?.velocity = SCNVector3Make(Float(CGFloat.random(in: -1...1)),
                                                                            01,
                                                                        Float(CGFloat.random(in: -1...1))) // 给予一个向上的初速度，模拟骰子落下
            
            
        }
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            
            let f = getTopFaceIndex(node: node)
            updateScore(with: f)
            
            
        }


    }
    
    func rollDice(diceNode : SCNNode) {
        
        // 先移除旧向量
        for node in self.narmalNodes.nNodes {
            node.removeFromParentNode();
        }
        
        self.narmalNodes.nNodes.removeAll()
        
        // 1. 隐藏骰子的物理效果，以便直接控制其动画
        diceNode.physicsBody?.isAffectedByGravity = false
        diceNode.physicsBody?.velocity = SCNVector3.init(x: 0, y: 0, z: 0)

        // 2. 应用随机旋转力来模拟摇动
        let rotationAngle = Float.random(in: 0..<2 * Float(CGFloat.pi)) // 随机旋转角度
        let rotationAxis = self.normalize(vector: SCNVector3(x: Float(CGFloat.random(in: -1...1)),
                                                      y: Float(CGFloat.random(in: -1...1)),
                                                      z: Float(CGFloat.random(in: -1...1)))) // 随机旋转轴
        let rotationDuration: TimeInterval = 1.0 // 摇动持续时间，可根据需要调整
        diceNode.runAction(SCNAction.rotateBy(x: CGFloat(rotationAngle),
                                               y: CGFloat(rotationAngle),
                                               z: CGFloat(rotationAngle),
                                               duration: rotationDuration),
                           forKey: "rollAction")
        
        // 3. 在动画结束后，恢复物理效果并检测点数
        DispatchQueue.main.asyncAfter(deadline: .now() + rotationDuration) {
            diceNode.physicsBody?.isAffectedByGravity = true
            diceNode.physicsBody?.velocity = SCNVector3Make(Float(CGFloat.random(in: -0.1...0.1)),
                                                                            0.2,
                                                                        Float(CGFloat.random(in: -0.1...0.1))) // 给予一个向上的初速度，模拟骰子落下
        }
        
//        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
//            
//            let f = getTopFaceIndex(node: diceNode)
//            updateScore(with: f)
//            
//        }
        
    }

    func normalize(vector: SCNVector3) -> SCNVector3 {
        let length = sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z)
        // 防止除以零错误，如果向量长度接近0，则返回一个默认值或者处理这种情况
        guard length != 0 else {
            return SCNVector3Zero // 或者返回一个默认的非零向量，比如(1, 1, 1)
        }
        return SCNVector3Make(vector.x / length, vector.y / length, vector.z / length)
    }

    func getVertices(from geometrySource: SCNGeometrySource) -> [SCNVector3] {
        let stride = geometrySource.dataStride / geometrySource.bytesPerComponent
        let offset = geometrySource.dataOffset / geometrySource.bytesPerComponent
        let vectorCount = geometrySource.vectorCount

        return geometrySource.data.withUnsafeBytes { (buffer: UnsafePointer<Float>) -> [SCNVector3] in
            var result = [SCNVector3]()
            for i in 0..<vectorCount {
                let start = i * stride + offset
//                result.append(SCNVector3(buffer[start], buffer[start + 1], buffer[start + 2]))
                let x = round(buffer[start] * 100) / 100
                let y = round(buffer[start + 1] * 100) / 100
                let z = round(buffer[start + 2] * 100) / 100
                result.append(SCNVector3(x, y, z))
            }
            return result
        }
    }
    
    func getTopFaceIndex(node: SCNNode) -> Int {
        
        // 先移除旧向量
        for node in self.narmalNodes.nNodes {
            node.removeFromParentNode();
        }
        
        self.narmalNodes.nNodes.removeAll()
        
        let box = node.geometry
        
        // 计算并获取每个面的法向量
        let n = node.geometry?.sources(for: .normal)
        let v = node.geometry?.sources(for: .vertex)
        let i = node.geometry?.sources(for: .texcoord)
        
        let vertices = getVertices(from: v![0])
        let normals = getVertices(from: n![0])
        
        var max_Y_value : Float = 0.0
        var max_index = 0
        
        var index = 0;
        for vertex in vertices {
            
            print("顶点index: \(index)")
            
            let normal = normals[index];
        
            let roundV = roundThePoint(pPoint: vertex)
            let roundN = roundThePoint(pPoint: normal)
            
            print("结束顶点坐标: \(roundV.x), \(roundV.y), \(roundV.z)")
            print("结束法线向量: \(roundN.x), \(roundN.y), \(roundN.z)")
            
            let endVertex = SCNVector3(x: roundV.x + roundN.x,
                                       y: roundV.y + roundN.y,
                                       z: roundV.z + roundN.z)
            
            print("结束法线向量终点: \(endVertex.x), \(endVertex.y), \(endVertex.z)")
            
            let worldPoint = trangeToWordpoint(node: node, localPoint: roundV)
            print("结束顶点世界坐标: \(worldPoint.x), \(worldPoint.y), \(worldPoint.z)")
            
            let worldEndPoint = trangeToWordpoint(node: node, localPoint: endVertex)
            print("结束法线向量终点: \(worldEndPoint.x), \(worldEndPoint.y), \(worldEndPoint.z)")
            
            let worldNormal = SCNVector3(x: worldEndPoint.x - worldPoint.x,
                                         y: worldEndPoint.y - worldPoint.y,
                                         z: worldEndPoint.z - worldPoint.z)
            let roundWorldNormal = roundThePoint(pPoint: worldNormal)
            print("结束世界法线向量: \(roundWorldNormal.x), \(roundWorldNormal.y), \(roundWorldNormal.z)")
            
            //画出法向量
            
            if (index >= 0 && index < 4) {
                drawAline(startPoint: vertex, endPoint: endVertex, onNode: node)
                drawAline(startPoint: worldPoint, endPoint: worldEndPoint, onNode: scene.rootNode)
            }
            
            
            if ((roundWorldNormal.y - max_Y_value) > 0) {
                max_Y_value = roundWorldNormal.y
                max_index = index
            }
            
            index += 1
            
            print("\n")
        }
        
        
        print("结束后最大index: \(max_index) 最大Y值：\(max_Y_value)")
        
        let faceIndex = max_index / 4
        
        return faceIndex + 1;
    }

    
    func updateScore(with faceIndex: Int) {
        // 更新玩家分数或检查是否完成任务
        print("向上面数是: \(faceIndex)")
        
//        self.showAlert = true
//        self.alertText = "向上面数是: \(faceIndex)"
//        let alert = UIAlertController(title: "结果显示", message: "向上面数是: \(faceIndex)", preferredStyle: UIAlertController.Style.alert)
//        UIApplication().keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)

    }
    
    func trangeToWordpoint(node: SCNNode, localPoint: SCNVector3) -> SCNVector3 {
        
        
        
//        let simdLocalPoint = simd_float4(localPoint.x, localPoint.y, localPoint.z, 1.0)
//        let simdWorldPoint = simdLocalPoint * node.simdWorldTransform.inverse
//        let worldPoint = SCNVector3(x: simdWorldPoint.x, y: simdWorldPoint.y, z: simdWorldPoint.z)
        
        let pNode = node.presentation
        let worldPoint = pNode.convertPosition(localPoint, to: nil)
        
        return roundThePoint(pPoint: worldPoint)
    }
    
    func roundThePoint(pPoint: SCNVector3)->SCNVector3 {
        let x = round(pPoint.x * 100) / 100
        let y = round(pPoint.y * 100) / 100
        let z = round(pPoint.z * 100) / 100
        
        return SCNVector3(x: x, y: y, z: z)
    }

    func drawAline(startPoint: SCNVector3, endPoint: SCNVector3, onNode: SCNNode)
    {
        // 创建一个表示法向量的线段
        // 定义线段的两个端点

        // 计算线段的长度
        let length = sqrt(pow(endPoint.x - startPoint.x, 2) + pow(endPoint.y - startPoint.y, 2) + pow(endPoint.z - startPoint.z, 2))

        // 创建一个线段几何体
        let vertices: [SCNVector3] = [startPoint, endPoint]
        let sources = [SCNGeometrySource(vertices: vertices)]
        let indices: [UInt32] = [0, 1]
        let elements = [SCNGeometryElement(indices: indices, primitiveType: .line)]

        let lineGeometry = SCNGeometry(sources: sources, elements: elements)

        // 设置线段的材质
        lineGeometry.firstMaterial?.diffuse.contents = UIColor.red

        // 创建一个节点来包含这个线段
        let lineNode = SCNNode(geometry: lineGeometry)

        // 将线段节点附加到原节点上，并调整位置
        lineNode.position = startPoint // 使线段的起点与节点位置一致
        onNode.addChildNode(lineNode)

        self.narmalNodes.nNodes.append(lineNode)
    }
    
    func createTextTexture(text: String, font: UIFont, color: UIColor, bgColor: UIColor) -> UIImage {
        let size = CGSize(width: 256, height: 256)
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
        let context = UIGraphicsGetCurrentContext()!
        // 绘制背景色
        context.setFillColor(bgColor.cgColor)
        context.fill(CGRect(origin:.zero, size: size))
        
        context.setFillColor(color.cgColor)
        
        let attributes = [NSAttributedString.Key.font: font]
        let textRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        text.draw(in: textRect, withAttributes: attributes)
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image
    }

    
    func creatFloor()
    {
        // 创建地面
        let groundGeometry = SCNPlane(width: 20.0, height: 20.0) // 宽度和高度定义了地面的大小
        let groundNode = SCNNode(geometry: groundGeometry) // 将几何体转化为一个节点

        // 应用地面材质
        let groundMaterial = SCNMaterial()
        groundMaterial.lightingModel = .physicallyBased
        groundMaterial.writesToDepthBuffer = true
        groundMaterial.diffuse.contents = UIColor.gray // 设置地面颜色，这里设置为灰色
        groundGeometry.materials = [groundMaterial] // 将材质应用到几何体上

        // 设置地面位置
        groundNode.position = SCNVector3(x: 0, y: -1, z: 0) // 设置地面在世界坐标系中的位置，y=0通常表示地面
        
        // 旋转节点使其朝向Y轴正方向
        groundNode.eulerAngles = SCNVector3(x: -.pi / 2, y: 0, z: 0) // π/2等于90度，绕X轴旋转

        groundNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: groundGeometry, options: nil))
//        groundNode.physicsBody?.categoryBitMask = 3
//        groundNode.physicsBody?.contactTestBitMask = 2
        groundNode.name = "我是地面"
        
        // 添加地面到场景
        scene.rootNode.addChildNode(groundNode)
        
    }
    
    func addAxis() {
        // 定义坐标轴长度和线宽
        let axisLength: CGFloat = 10.0
        let lineWidth: CGFloat = 0.05

        // 创建X轴（红色）
        let xAxisGeometry = SCNBox(width: lineWidth, height: axisLength, length: lineWidth, chamferRadius: 0)
        xAxisGeometry.firstMaterial?.diffuse.contents = UIColor.red
        let xAxisNode = SCNNode(geometry: xAxisGeometry)
        xAxisNode.rotation = SCNVector4(0, 0, 1, -Float.pi / 2) // 旋转X轴水平指向右
//        xAxisNode.position = SCNVector3(axisLength / 2, 0, 0) // 移动到X轴末端
        scene.rootNode.addChildNode(xAxisNode)

        // 创建Y轴（绿色）
        let yAxisGeometry = SCNBox(width: lineWidth, height: axisLength, length: lineWidth, chamferRadius: 0)
        yAxisGeometry.firstMaterial?.diffuse.contents = UIColor.green
        let yAxisNode = SCNNode(geometry: yAxisGeometry) // Y轴默认竖直
//        yAxisNode.position = SCNVector3(0, axisLength / 2, 0) // 移动到Y轴末端
        scene.rootNode.addChildNode(yAxisNode)

        // 创建Z轴（蓝色）
        let zAxisGeometry = SCNBox(width: lineWidth, height: axisLength, length: lineWidth, chamferRadius: 0)
        zAxisGeometry.firstMaterial?.diffuse.contents = UIColor.blue
        let zAxisNode = SCNNode(geometry: zAxisGeometry)
        zAxisNode.rotation = SCNVector4(1, 0, 0, -Float.pi / 2) // 旋转Z轴使其垂直屏幕
//        zAxisNode.position = SCNVector3(0, 0, axisLength / 2) // 移动到Z轴末端
        scene.rootNode.addChildNode(zAxisNode)
    }
    
    func addFreeObj()
    {
        // 创建一个SCNCylinder
        let cylinderRadius: CGFloat = 0.5 // 圆柱半径
        let cylinderHeight: CGFloat = 2.0 // 圆柱高度
        let cylinder = SCNCylinder(radius: cylinderRadius, height: cylinderHeight)

        cylinder.firstMaterial?.diffuse.contents = UIColor.yellow
        
        // 可选：更改圆柱的分段数以获得更平滑或更粗糙的外观
        // cylinder.radialSegmentCount = 24 // 经向分段数，默认值已经足够平滑，一般不需要更改
        // cylinder.heightSegmentCount = 1 // 纵向分段数，默认为1

        // 为圆柱创建一个节点并添加到场景中
        let cylinderNode = SCNNode(geometry: cylinder)
        cylinderNode.position = SCNVector3(x: 0, y: 3, z: Float(cylinderHeight) / 2) // 将圆柱置于场景中心，沿Z轴向上移动一半高度，确保底部位于原点
        cylinderNode.name = "我是自由的"
        
        cylinderNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(geometry: cylinder, options: nil))
//        cylinderNode.physicsBody?.mass = 1.0
//        cylinderNode.physicsBody?.friction = 0.5
//        cylinderNode.physicsBody?.restitution = 0.3 // 弹性
        
        cylinderNode.physicsBody?.categoryBitMask = CategoryPlayer // 一个唯一标识
//        cylinderNode.physicsBody?.collisionBitMask = CategoryEnemy // 允许与另一类碰撞
        cylinderNode.physicsBody?.contactTestBitMask = CategoryEnemy
        
        scene.rootNode.addChildNode(cylinderNode)
    }
    
    func addFreeObj2()
    {
        // 创建一个SCNCylinder
        let cylinderRadius: CGFloat = 0.5 // 圆柱半径
        let cylinderHeight: CGFloat = 1.0 // 圆柱高度
        let cylinder = SCNCylinder(radius: cylinderRadius, height: cylinderHeight)
        
        cylinder.firstMaterial?.diffuse.contents = UIColor.yellow
        
        // 可选：更改圆柱的分段数以获得更平滑或更粗糙的外观
        // cylinder.radialSegmentCount = 24 // 经向分段数，默认值已经足够平滑，一般不需要更改
        // cylinder.heightSegmentCount = 1 // 纵向分段数，默认为1
        
        // 为圆柱创建一个节点并添加到场景中
        let cylinderNode = SCNNode(geometry: cylinder)
        cylinderNode.name = "我是自由的2"
        
        cylinderNode.position = SCNVector3(x: 0, y: 1, z: Float(2) / 2) // 将圆柱置于场景中心，沿Z轴向上移动一半高度，确保底部位于原点
        
        cylinderNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(geometry: cylinder, options: nil))
//        cylinderNode.physicsBody?.mass = 1.0
//        cylinderNode.physicsBody?.friction = 0.5
//        cylinderNode.physicsBody?.restitution = 0.3 // 弹性
        cylinderNode.physicsBody?.categoryBitMask = CategoryEnemy // 一个唯一标识
//        cylinderNode.physicsBody?.collisionBitMask = 1 // 允许与另一类碰撞
//        cylinderNode.physicsBody?.contactTestBitMask = CategoryPlayer  允许与另一类碰撞


        scene.rootNode.addChildNode(cylinderNode)
    }
    

    func addCustomFreeObj()
    {
        // 创建一个SCNCylinder
        let cylinderRadius: CGFloat = 0.5 // 圆柱半径
        let cylinderHeight: CGFloat = 2.0 // 圆柱高度
        let cylinder = SCNCylinder(radius: cylinderRadius, height: cylinderHeight)
        
        cylinder.firstMaterial?.diffuse.contents = UIColor.yellow
        
        // 可选：更改圆柱的分段数以获得更平滑或更粗糙的外观
        // cylinder.radialSegmentCount = 24 // 经向分段数，默认值已经足够平滑，一般不需要更改
        // cylinder.heightSegmentCount = 1 // 纵向分段数，默认为1
        
        // 为圆柱创建一个节点并添加到场景中
        let cylinderNode = SCNNode(geometry: cylinder)
        cylinderNode.name = "我是自由的"
        
        let customNode = BaseNode()
        customNode.position = SCNVector3(x: 1, y: 1, z: Float(cylinderHeight) / 2) // 将圆柱置于场景中心，沿Z轴向上移动一半高度，确保底部位于原点
        customNode.addChildNode(cylinderNode)
        scene.rootNode.addChildNode(customNode)
        
        // 使用SCNTransaction开始一个动画块
        SCNTransaction.begin()
        SCNTransaction.animationDuration = 10.0 // 动画持续时间
        SCNTransaction.animationTimingFunction = CAMediaTimingFunction(name: .easeInEaseOut) // 动画缓动效果

        // 旋转节点
        cylinderNode.rotation = SCNVector4(1, 0, 0, Float.pi * 2) // 使节点围绕Y轴旋转360度

        // 结束动画块
        SCNTransaction.commit()
    }



}
#Preview {
    ThreeDDemoView()
}
